
/*
 *  Copyright 2007 Marc Lanctot and Marc Gendron-Bellemare
 *
 *  This file is part of OpenMTG.
 *
 *  OpenMTG is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  OpenMTG is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with OpenMTG.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

import java.util.*;

public class Card
{
  private String name;

  // Card ID. 
  //
  // Refers to the functional spec of a card. 
  // Eg. Every Savannah Lions card will have the same cid. 
  private int cid;   

  // Instand ID. 
  //
  // Each individual card in a given game has a different instance id. 
  // Set at the beginning of the game. 
  private int iid; 

  // Owner ID. 
  //
  // Who owns this card? Corresponds to a player id. 
  private int oid;


  private boolean isPermanent=true;

	private HashSet<String> type;

  public static final String TYPE_LAND               = "L";
  public static final String TYPE_CREATURE           = "C";
  public static final String TYPE_SORCERY            = "S";
  public static final String TYPE_INSTANT            = "I";
  public static final String TYPE_ARTIFACT           = "A";
  public static final String TYPE_ENCHANTMENT        = "E";
  public static final String TYPE_AURA               = "U";

  private String subType;

  public int power, toughness;
	public int damage;
  public String cost;
  
  private ArrayList<CardEffect> effects; 

  private ArrayList<Character> permAbilities;     // non-triggered abilities
  public static final char AB_FLYING               = 'F';

  private boolean attacking;
  private boolean tapped; 
	private boolean summoningSickness;

  // for lands
  public Card(String name, String[] types)
  {
    permAbilities = new ArrayList<Character>();
    effects = new ArrayList<CardEffect>();
    this.name = name;
  
		type = new HashSet<String>();
		
		for (int i = 0; i < types.length; i++)
			type.add(types[i]);	
	}

  // for sorceries, instants, artifacts, and enchantments
  public Card(String name, String[] types, String cost)
  {
		this(name,types);
    this.cost = cost;
    if (isSorcery() || isInstant())
      isPermanent=false;
  }

  // for auras
  public Card(String name, String[] types, String cost, String subType)
  {
		this(name,types,cost);
    this.subType = subType;
  }

  // for creatures
  public Card(String name, String[] types, String cost, String subType,
              int power, int toughness)
  {
		this(name,types,cost,subType);

    this.power = power;
    this.toughness = toughness;
  }

  public void setIID(int iid) {
    this.iid = iid;
  }

  public int getIID() { 
    return iid; 
  }

  public void setCID(int cid) {
    this.cid = cid;
  }

	public int getCID() {
		return cid;
	}
	
  public void setOID(int oid) { 
    this.oid = oid;
  }

  public int getOID() { 
    return oid;
  }
  
  public void addEffect(CardEffect ce) {
    effects.add(ce);
  }
  
  public CardEffect getMainEffect() {
    return effects.get(0);
  }
  
  public void init(int oid) {
    iid = Helpers.nextIid();
    this.oid = oid;
  }

  public String getName() {
    return name;
  }
  public HashSet<String> getType() {
    return type;
  }
  public String getCost() {
    return cost;
  }
  public String getSubType() {
    return subType;
  }
  public int getPower() {
    return power;
  }
  public int getToughness() {
    return toughness;
  }
	public boolean getTapped() {
		return tapped;
	}

	public boolean getSickness() {
		return summoningSickness;
	}

	public boolean getPermanent() {
		return isPermanent;
	}

	public void setSickness(boolean pSick) {
		summoningSickness = pSick;
	}
	
	public void setAttacking(boolean atk) {
	  attacking = atk;
	}
	   
	public boolean isAttacking() {
	  return attacking;
	}
	   
	
  public void tap() { 
    tapped = true;
  }

  public void untap() {
    tapped = false; 
  }

	public boolean isTappable()
	{
		// @@@ here's a question: is a tapped card tappable? e.g. icy manipulator
		if (tapped) return false;
		else if (isCreature() && summoningSickness) return false;
		else return true;
	}
	
	public boolean addDamage(int pDamage)
	{
		damage += pDamage;
		if (damage >= getToughness()) return true;
		else return false;
	}
  public void addPermAbility(char ab)
  {
    permAbilities.add(ab);
  }

  public boolean isBasicLand()
  {
    if (!isLand())
      return false;

    if (   name.equals("Plains")
        || name.equals("Forest")
        || name.equals("Island")
        || name.equals("Mountain")
        || name.equals("Swamp") )
      return true;

    return false;
  }
  
  public String producesMana()
  {
    if (!isLand())
      return ""; 
    
    if      (name.equals("Plains")) return "W"; 
    else if (name.equals("Forest")) return "G"; 
    else if (name.equals("Island")) return "U"; 
    else if (name.equals("Mountain")) return "R"; 
    else if (name.equals("Swamp")) return "B";
    
    return ""; 
  }

	public boolean isLand()
	{
		return (type.contains(TYPE_LAND));
	}
	
	public boolean isCreature()
	{
		if (type.contains(TYPE_CREATURE))
			return true;
		else
			return false;
	}
	
	public boolean isSorcery()
	{
		return (type.contains(TYPE_SORCERY));
	}

	public boolean isInstant()
	{
		return (type.contains(TYPE_INSTANT));
	}

	public boolean isWall()
	{
		return false;
	}
	
	public boolean isTapped() 
	{
	  return tapped; 
	}
	
	public boolean isUntapped()
	{
	  return !tapped; 
	}
	
  // TODO: we're going to need to store a database of cards eventually..  for now i've just hardcoded the following..
  public static Card int2Card(int theInt){

    Card theCard=null;
    CardLoader cl = new CardLoader();
    return cl.getCard(theInt);

  }

  public String encode() { 
    return (cid + "," + iid);
  }

  public void decode(String s) {
    String[] parts = s.split(",");
    cid = Integer.parseInt(parts[0]);
    iid = Integer.parseInt(parts[1]); 
  }

  public String toString(){
    String s = (getName()+","+cid+","+iid);
    
    if (tapped)
      s += " (T)";
   	if (summoningSickness)
			s += " (S)";
   	if (attacking)
   	  s += " (A)"; 

    return s;
  }

	/** Returns true if it is possible to cast this spell presently. */
	public boolean validCastPhase(PhaseInfo.Phase pPhase)
	{
		// Before this is implemented, fix types to be bit maps
		return true;
	}

	/** Returns whether a particular card (creature!) can attack this turn.
	  * Note that this does not depend on the phase. */
		
	public boolean canAttack()
	{
		// Add special effects here as desired
		return (   isCreature() 
		        && !tapped 
		        && isTappable()
		        && !isWall()
		        && !summoningSickness
		        && !attacking);
	}
	
	public boolean isOnTurnOnlyCast() 
	{
    if (   type.contains(TYPE_CREATURE)
        || type.contains(TYPE_ARTIFACT)
        || type.contains(TYPE_ENCHANTMENT)
        || type.contains(TYPE_AURA)
        || type.contains(TYPE_SORCERY)   )
      return true;
    
    return false;
	}
	
	public boolean canCastInResponse() 
	{
	  if (type.contains(TYPE_INSTANT))
	    return true;
	  
	  return false;
	}
	
  public String getColors() 
  {
    String clrs = "";
    
    for (int i = 0; i < cost.length(); i++)
    {
      char ch = cost.charAt(i);
      
      if (Character.isLetter(ch) && clrs.indexOf(ch) < 0)
        clrs += ch;
    }
    
    return clrs;
  }
  
	public static void main(String[] args)
  {
    Card c1 = new Card("Forest", new String[] { TYPE_LAND } );

    // sweeet....
    Card c2 = new Card("Scryb Sprites", new String[] {TYPE_CREATURE}, 
			"G", "Sprites", 1, 1);
    c2.addPermAbility(AB_FLYING);
  }

}

